/*
 * Copyright 2002-2006 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package de.riceman.simpleGo.view.views.visualizationView;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.lang.reflect.InvocationTargetException;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Observable;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultCaret;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.richclient.application.Application;
import org.springframework.richclient.application.docking.vldocking.VLDockingViewDescriptor;
import org.springframework.richclient.application.support.AbstractView;
import org.springframework.richclient.command.ActionCommand;

import de.riceman.simpleGo.SimpleGo;
import de.riceman.simpleGo.events.SimpleGoLifecycleApplicationEvent;
import de.riceman.simpleGo.main.BitMatrix;
import de.riceman.simpleGo.main.GoGame;

/**
 * This class defines the initial view to be presented in the SimpleGo application. It is
 * constructed automatically by the platform and configured according to the bean
 * specification in the application context.
 * 
 * @author Larry Streepy
 * 
 */
public class VisualizationView extends AbstractView implements ApplicationListener, ApplicationContextAware {

	private static final Log logger = LogFactory.getLog(VisualizationView.class);
	
	//private ApplicationContext ctx;
	ForceDirectedGraphLayouter map;
	
	private AbstractSet<SpringEdge> edges;
	private AbstractSet<ForcedNode> nodes;
	
	private JPanel graphPanel;
	private JPanel panel;
	//private JScrollPane scrollPane;
	private GoGame goGame;
	
	//private int width;
	//private int height;	
	
	
	public VisualizationView() {
		if (logger.isInfoEnabled()) {
			logger.info("VisualizationView OBJECT CREATED.");
		}
	}
    /**
     * Create the actual UI control for this view. It will be placed into the window
     * according to the layout of the page holding this view.
     */
    protected JComponent createControl() {    	

        panel = getComponentFactory().createPanel(new BorderLayout());
		
        return panel;
    }
	
    private void init() {
    	ForceDirectedGraph fdg = new ForceDirectedGraph(goGame.getConfiguration().getAdjacencies(), 100, 0.1, 10, 15);
    	fdg.initialize();
    	
    	map = new ForceDirectedGraphLayouter(0.0001, 1.0, 200, new Timer(), fdg);
    	
    	map.run();
    	
    	edges = map.getGraph().getEdges();
		nodes = map.getGraph().getNodes();

		
		graphPanel = new JPanel() {

			private static final long	serialVersionUID	= 1L;

			protected void paintChildren( Graphics g )
			{
				System.out.println("visualizationView.getGraphPanel().paintChildren() called.");
				
				Iterator<SpringEdge> edgeIt = edges.iterator();

				SpringEdge e;
				ForcedNode n;
				setBackground( Color.LIGHT_GRAY );
				
				Graphics2D g2d = (Graphics2D)g;
				g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				        RenderingHints.VALUE_ANTIALIAS_ON);
				g2d.setStroke(new BasicStroke(1));
				
				Iterator<ForcedNode> nodeIt = nodes.iterator(); 
				
				while (nodeIt.hasNext()) {
					n = nodeIt.next();
					g2d.draw(getGraphicsObject(n));
					System.out.println(n);
				}
				
				while (edgeIt.hasNext()) {
					e = edgeIt.next();
					Line2D.Double v = new Line2D.Double();
					
					// Mittelpunkte der 2 Knoten: (x1,y1), (x2,y2)
					double x1 = getGraphicsObject(e.getVertexA()).getCenterX();
					double y1 = getGraphicsObject(e.getVertexA()).getCenterY();
					double x2 = getGraphicsObject(e.getVertexB()).getCenterX();
					double y2 = getGraphicsObject(e.getVertexB()).getCenterY();
					
					// Entfernung der Mittelpunkte voneinander: d
					double d = Point2D.distance( x1, y1, x2, y2 );
					
					// Radius der Knoten: r
					double r1 = e.getVertexA().getDiameter() / 2.0;
					double r2 = e.getVertexB().getDiameter() / 2.0;
					
					// Schnittpunkt der Geraden mit dem Knotenaussenkreis: s1, s2
					Point2D.Double s1 = new Point2D.Double(
						x1 + r1/d * (x2-x1),
						y1 + r1/d * (y2-y1)
					);
		
					Point2D.Double s2 = new Point2D.Double(
						x2 + r2/d * (x1-x2),
						y2 + r2/d * (y1-y2)
					);
					
					// Verbindung neu setzten: Start-/Zielpunkt setzten
					v.setLine(s1, s2);
					
					g2d.draw(v);
				}
			}
		};

		graphPanel.addMouseListener(new MouseAdapter() { 
          public void mouseReleased(MouseEvent me) {
        	  Application.instance().getApplicationContext().publishEvent(
              		new SimpleGoLifecycleApplicationEvent(SimpleGoLifecycleApplicationEvent.MOVE_VIA_GUI, this));
            //System.out.println(me); 
          } 
        } );
		
		//scrollPane = new JScrollPane(graphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		
		//panel.add(scrollPane);
		//scrollPane.setVisible(true);
		//scrollPane.repaint();
		panel.add(graphPanel);
		graphPanel.repaint();
		graphPanel.setVisible(true);
		panel.repaint();
		panel.setVisible(true);
		
		
    	
		//this.getControl().add(scrollPane);
		
		
		//scrollPane.removeAll();
		//scrollPane.validate();
		//scrollPane.repaint();
		//scrollPane.revalidate();
		
		System.out.println("I wanna repaint now!");
		
		Application.instance().getActiveWindow().getControl().repaint();
		
		this.getControl().repaint();
		this.getControl().setVisible(true);
		this.getControl().getParent().setVisible(true);
		
		VLDockingViewDescriptor view = (VLDockingViewDescriptor) Application.instance().getApplicationContext().getBean("visualizationView");
    	ActionCommand cmd = view.createShowViewCommand(getActiveWindow());
    	cmd.execute();

		//graphPanel.repaint();
		//scrollPane.removeAll();
		
		
		//panel.getParent().validate();
		//panel.revalidate();
		//panel.repaint();
		
		//panel.revalidate();
		//graphPanel.revalidate();
		//scrollPane.validate();
    	//scrollPane.doLayout();
		
    }
    
	private JPanel getGraphPanel() {
		System.out.println("visualizationView.getGraph() called.");
		
		
		return graphPanel;
	}
	

	public void update() {

		//final ForceDirectedGraphLayouter map = (ForceDirectedGraphLayouter) obs;
		System.out.println("update()");
		
		edges = map.getGraph().getEdges();
		nodes = map.getGraph().getNodes();
		
			try {
				
				//using invokeLater crashes the proper display!!!
				SwingUtilities.invokeAndWait(new Runnable() {
					
					public void run() {
					
							
						//i = map.getStep();	
						//fetch the resulting net
							
						//GraphView.this.edges				= map.getEdges();
						//GraphView.this.nodes				= map.getNodes();	
							
						graphPanel = getGraphPanel();
						graphPanel.repaint();
						//panel.revalidate();
							
						/*iterationsLabel.setText("        iterations = " + Integer.toString(i));
						System.out.println(i);
						timeLabel.setText("        time = " + map.getTimer().getElapsedTime() + " ms");
						iterationsLabel.repaint();*/
					
						panel.repaint();
								
						//pack();
						
						/*try {
							 BufferedImage bufferedImage = paintComponent(panel);
							 ImageIO.write(bufferedImage, "jpg", new File(map.getStep() + ".jpg"));
							 
							 } catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							 }*/
					}
					
				});
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
	
	public Ellipse2D.Double getGraphicsObject(ForcedNode node) {
		
		Ellipse2D.Double v = new Ellipse2D.Double(node.getPosition().getX(), node.getPosition().getY(), node.getDiameter(), node.getDiameter());
		
		return v;
	}

	@Override
	public void onApplicationEvent(ApplicationEvent event) {

		if (event instanceof SimpleGoLifecycleApplicationEvent) {
			
			SimpleGoLifecycleApplicationEvent lcae = (SimpleGoLifecycleApplicationEvent) event;
			
			if (lcae.getEventType() == SimpleGoLifecycleApplicationEvent.INITIALIZED && lcae.objectIs(GoGame.class)) {
		    	goGame = (GoGame) lcae.getObject();
		    	if (logger.isInfoEnabled()) {
					logger.info("VisualizationView received INITIALIZED.");
				}
		    	this.init();
		    	//VLDockingViewDescriptor view = (VLDockingViewDescriptor) Application.instance().getApplicationContext().getBean("visualizationView");
		    	//view.createShowViewCommand(getActiveWindow());
		    	
		    } else if (lcae.getEventType() == SimpleGoLifecycleApplicationEvent.MOVED && lcae.objectIs(GoGame.class)) {
		    	if (logger.isInfoEnabled()) {
					logger.info("VisualizationView received MOVED.");
				}
		    	//this.update();
		    }
		}
	}
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		//this.ctx = applicationContext;
		
	}
	
	
}
